package com.example.study.juejin

import java.lang.reflect.InvocationHandler
import java.lang.reflect.Method
import java.lang.reflect.Proxy

/**
 *  created by 20300
 *   on 2022/3/21
 *   describe:https://juejin.cn/post/6935029399125262349
 */
class 易懂的动态代理 {
/*
代理是最基本的设计模式之一,它能够插入一个用来替代"实际"对象的"代理"对象,
来提供额外的或不同的操作.以及这些操作通常设计与"实际"对象的通信,因此"代理"
对象通常充当中间人的角色

代理模式
代理对象为"实际"对象提供一个替身或占位符以控制对这个"实际"对象的访问.被代理的对象
可以是远程的对象,创建开销大的对象或需要安全控制的对象.以下类图根据链接

再来看以下对应代码,这是IObject接口,真实对象RealObj和代理对象ObjProsy都实现此接口:
*/
    interface IObject{
        fun request()
    }
    /*RealObj是实际处理request()逻辑的对象,但是出于设计的考量,需要对RealObj内部的方法
    调用进行控制访问*/

    class RealObject :IObject{
        override fun request() {
            //模拟操作
        }

    }
    /*
ObjProxy是RealObj的代理类,其同样实现了IObject接口,所以具有相同对外方法.
客户端与RealObj的所有交互都必须通过ObjProsy
*/
    class ObjProsy : IObject{
        private lateinit var realT:IObject
        constructor(t:IObject){
            realT = t
        }
        override fun request() {
            if (isAllow()) realT.request()
        }
        fun isAllow():Boolean{
            return true
        }

    }
    /*动态代理
    java的动态代理可以动态的创建代理并动态的处理所代理方法的调用,在动态代理上所做的所以调用都会被重定向
    到单一的调用处理器上,它的工作是揭示调用的类型并确定相应的策略.类图如链接*/

    /*这是InvocationHandler的实现类,类图中Prosy的方法调用都会被系统传入此类,即invoke方法,而ObjProxy
    Handler又持有RealObject实例,所以ObjProsyHandler是"真正"对RealObject对象进行访问控制的代理类*/
    class ObjProxyHandler : InvocationHandler{
        lateinit var realT:IObject
        constructor(t:IObject){
            realT = t
        }
        override fun invoke(p0: Any?, p1: Method?, p2: Array<out Any>?): Any {
            if (p1?.name=="request"&&!isAllow())return Any()
            if (p1 != null) {
                return p1.invoke(realT,p2)
            }
            return Any()
        }
        fun isAllow():Boolean{
            return false
        }
    }
    /*RealObj是实际处理request()逻辑的对象*/
    /*动态代理的使用方法如下:我们通过Proxy.newProxyInstance静态方法来创建代理,其参数如下,
    一个类加载器,一个代理实现的接口列表,一个InvocationHandler的接口实现
        public void startTest() {
        IObject proxy = (IObject) Proxy.newProxyInstance(
                IObject.class.getClassLoader(),
                new Class[]{IObject.class},
                new ObjProxyHandler(new RealObject()));
        proxy.request(); // ObjProxyHandler的invoke方法会被调用
    }
*/

    /*Proxy源码解析:https://juejin.cn/post/6935029399125262349*/

}

